# coding=utf-8
"""
author: jamon
"""
from typing import List, Union, Dict

import pygame

from client.model.gate_data import GateData
from package.static.const import TypeIdConst, MoveDirection, HpStatus
from package.universe import TypeItem, universe, TankDogma

id_suffix: Dict[TypeIdConst, int] = {}


class Buff(object):
    """增减益buff"""
    def __init__(self, source: Union[TypeIdConst, str], duration: int,
                 abs_digit: float, rel_ratio: float, is_unique: bool = True, **kwargs):
        """

        :param source: 来自于哪类物品
        :param duration: 持续时间，帧数
        :param abs_digit: 绝对数值
        :param rel_ratio: 相对比列
        :param is_unique: 是否唯一，即同类物品的buff是否只能存在一个
        :param kwargs: 额外参数
        """
        self.source: Union[TypeIdConst, str] = source
        self.duration: int = duration
        self.abs_digit: float = abs_digit
        self.rel_ratio: float = rel_ratio
        self.is_unique: bool = is_unique
        self.kwargs = kwargs


class EntityBase(pygame.sprite.Sprite):

    @classmethod
    def gen_item_id(cls, type_id: TypeIdConst):
        if type_id in id_suffix:
            id_suffix[type_id] += 1
        else:
            id_suffix[type_id] = 1
        return type_id * 1000000 + id_suffix[type_id]

    def __init__(self, type_id: TypeIdConst, **kwargs):
        super(EntityBase, self).__init__()
        self.item_id: int = self.gen_item_id(type_id)
        self._type_id: TypeIdConst = type_id

        self.static_info: TypeItem = universe.get_type_base_info(type_id)
        self.dogma_info: TankDogma = universe.get_tank_special_info(type_id)

        self.direction: MoveDirection = MoveDirection.NONE

        # 初始化时，血量最大值
        self._cur_blood = self.static_info.max_blood
        self.max_blood: int = self.static_info.max_blood

        # 当前速度buff
        self._speed_buff: List[Buff] = []

        # 当前速度(无加成时)
        self._cur_raw_speed: int = self.static_info.max_speed

        self.is_dead: bool = False

    def add_buff(self, buff: Buff) -> None:
        if buff.is_unique:
            for b in self._speed_buff:
                if b.source == buff.source:
                    b.duration = buff.duration
                    return
        self._speed_buff.append(buff)

    def get_buff(self) -> float:
        result = 0
        for buff in self._speed_buff:
            result += buff.abs_digit + buff.rel_ratio * self._cur_raw_speed
        return result

    @property
    def real_speed(self):
        return max(0, int(self._cur_raw_speed + self.get_buff()))

    def tick_by_per_frame(self):
        # buff时间刷新
        for i in range(len(self._speed_buff) - 1, -1, -1):
            self._speed_buff[i].duration -= 1
            if 0 >= self._speed_buff[i].duration:
                del self._speed_buff[i]

        # 每秒自我回复
        if 0 == GateData().cur_physical_frame_no % GateData().frame_physical_rate:
            self._cur_blood += self.static_info.recovery
            self._cur_blood = min(self._cur_blood, self.max_blood)

    def can_remove(self) -> bool:
        return self.is_dead

    def receive_hurt(self, hurt_hp: int) -> int:
        """
        受伤处理
        :param hurt_hp: int
        :return: int
        """
        real_hurt = hurt_hp if hurt_hp > self.static_info.immune_hurt else 0
        if real_hurt >= self._cur_blood:
            # 真实伤害超过血量，则死亡
            self._cur_blood = 0
            self.is_dead = True
            return self._cur_blood

        self._cur_blood -= real_hurt
        return real_hurt

    def get_hp_status(self) -> HpStatus:
        if 0 >= self._cur_blood:
            return HpStatus.DEAD
        if self._cur_blood < self.max_blood:
            return HpStatus.BROKEN
        return HpStatus.NORMAL
